﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Oplaco.Core.BusinessLogicLayer;
using Oplaco.Core.Configuration;
using System.Data;
using System.Data.SqlClient;

namespace Oplaco.Web.DTO
{
    /// <summary>
    /// 
    /// </summary>
    public static class AdvertismentManager
    {
        #region members
        private static int[] NumCachedFeatures = new int[] {100, 110, 120, 140, 150};
        private const int CacheLifeTime = 1; // in minutes
        private static Random random = new Random();
        private const string CacheKeyPrefix = "AdvertismentsCache_";
        private static SiteSettings settings = Oplaco.Core.Configuration.SiteSettings.GetSharedSettings();
        #endregion

        #region Public

        /// <summary>
        /// Clears objects from the cache
        /// </summary>
        /// <param name="context"></param>
        public static void ClearCache(HttpContext context) {
            for (int x = 0; x < NumCachedFeatures.Count(); x++) { 
                context.Cache.Remove(GetCacheKey(NumCachedFeatures[x]));
            }

        }

        /// <summary>
        /// Fetches any Ad from cache or database 
        /// </summary>
        /// <param name="context">Http current context</param>
        /// <param name="maximumItems">Maximum amount of items to be fetched from database</param>
        /// <returns></returns>
        public static CachedAdvertismentCollection Fetch(HttpContext context, int maximumItems)
        {
            CachedAdvertismentCollection advColl = null;            
            Oplaco.Core.DAL.AdsDataComponent.AdsDataTable data;
            try
            {
                //custom cache handling
                if (context == null) Oplaco.Exceptions.AppService.ProcessAndNotifyBusinessLayerException(new Exception("Could not find the current HttpContext"));

                int featureCacheNumber = NumCachedFeatures[0]; //each method that needs to add its collection to the cache will have its unique cachekey,... 
                string cacheKey = GetCacheKey(featureCacheNumber);

                advColl = context.Cache[cacheKey] as CachedAdvertismentCollection;
                if (advColl == null)
                {
                    advColl = new CachedAdvertismentCollection();

                    data = AdsDB.GetActiveAdsByQuery(maximumItems, 0, 0, 10000000, String.Empty, String.Empty, (int)AdType.Unspecified, (int)AdLevel.Unspecified, settings.MaxAdRunningDays, false);

                    if (data != null && data.Count > 0)
                    {

                        CachedAdvertisment[] advArr = (from DataRow row in data.Rows
                                                       select new CachedAdvertisment((int)row["Id"],
                                                           (int)row["MemberId"], 
                                                           (int)row["CategoryId"], 
                                                           row["Title"].ToString(), 
                                                           row["CategoryName"].ToString(), 
                                                           CategoryManager.GetCategoryPath(context, (int)row["CategoryId"]), 
                                                           (decimal)row["Price"],
                                                           (int)row["AdType"],
                                                           (int)row["AdLevel"],
                                                           (int)row["AdStatus"],
                                                           (DateTime)row["DateCreated"], 
                                                           (DateTime)row["DateApproved"], 
                                                           (DateTime)row["ExpirationDate"], 
                                                           row["Description"].ToString(), 
                                                           row["Url"].ToString(), 
                                                           0)).ToArray<CachedAdvertisment>();

                        if (advArr != null && advArr.Count() > 0) advColl.CopyTo(advArr, 0);
                        DateTime expiration = DateTime.Now.AddMinutes(CacheLifeTime);
                        context.Cache.Add(cacheKey, advArr, null, expiration, TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Normal, null);
                    }
                }
            }
            catch (SqlException SQLEX)
            {
                Oplaco.Exceptions.AppService.ProcessAndNotifyDataAccessLayerException(SQLEX);
            }
            catch (Exception EX) {
                Oplaco.Exceptions.AppService.ProcessAndNotifyBusinessLayerException(EX);
            }
            return advColl;
        }

        /// <summary>
        /// Gets a single ad from database
        /// </summary>
        /// <param name="context">HttpContext</param>
        /// <param name="adid">advertisment id</param>
        /// <returns>cacheble ad</returns>
        public static CachedAdvertisment FetchSingle(HttpContext context, int adid) {
            CachedAdvertisment adv = null;  
            Oplaco.Core.DAL.AdsDataComponent.AdsRow row = AdsDB.GetAdById(adid);
              if (row != null)
              {

                  adv = new CachedAdvertisment((int)row["Id"], (int)row["MemberId"], (int)row["CategoryId"], row["Title"].ToString(), row["CategoryName"].ToString(), CategoryManager.GetCategoryPath(null, (int)row["CategoryId"]), (decimal)row["Price"],
                      (int)row["AdType"], (int)row["AdLevel"], (int)row["AdStatus"],
                      (DateTime)row["DateCreated"], (DateTime)row["DateApproved"], (DateTime)row["ExpirationDate"], row["Description"].ToString(), row["Url"].ToString(), 0);
              }

            return adv;
        }

        /// <summary>
        /// Fetches ads based on certain ad level from database, with caching, this is the preferred method!
        /// </summary>
        /// <param name="context">Http current context</param>
        /// <param name="maximumItems">max of items to be retrieved</param>
        /// <param name="adlevel">Level of the ad : featured,normal,unspecified </param>
        /// <param name="withImages">Should the collection also hold image ids?</param>
        /// <returns>Cached ads Collection object</returns>
        public static CachedAdvertismentCollection FetchByAdLevel(HttpContext context, int maximumItems, AdLevel adlevel, bool withImages)
        {            
            Oplaco.Core.DAL.AdsDataComponent.AdsDataTable data;
            CachedAdvertisment[] advArr = null;
            CachedAdvertismentCollection advColl = null;
            try
            {
                //custom cache handling
                if (context == null) Oplaco.Exceptions.AppService.ProcessAndNotifyBusinessLayerException(new Exception("Could not find the current HttpContext"));

                
                string cacheKey = GetCacheKey(NumCachedFeatures[1]);

                advColl = context.Cache[cacheKey] as CachedAdvertismentCollection;
                if (advColl == null)
                {
                    advColl = new CachedAdvertismentCollection();
                    data = AdsDB.GetActiveAdsByQuery(maximumItems, 0, 0, 10000000, String.Empty, String.Empty, (int)AdType.Unspecified, (int)AdLevel.Unspecified, settings.MaxAdRunningDays, withImages);

                    if (data != null && data.Count > 0)
                    {
                        if (withImages)
                        {
                            advArr = (from DataRow row in data.Rows
                                      select new CachedAdvertisment((int)row["Id"],
                                          (int)row["MemberId"], (int)row["CategoryId"], row["Title"].ToString(), row["CategoryName"].ToString(), CategoryManager.GetCategoryPath(context, (int)row["CategoryId"]), (decimal)row["Price"],
                                          (int)row["AdType"], (int)row["AdLevel"], (int)row["AdStatus"],
                                          (DateTime)row["DateCreated"], (DateTime)row["DateApproved"], (DateTime)row["ExpirationDate"], row["Description"].ToString(), row["Url"].ToString(), (int)row["PreviewImageId"])).ToArray<CachedAdvertisment>();
                        }
                        else
                        {
                            advArr = (from DataRow row in data.Rows
                                      select new CachedAdvertisment((int)row["Id"],
                                          (int)row["MemberId"], (int)row["CategoryId"], row["Title"].ToString(), row["CategoryName"].ToString(), CategoryManager.GetCategoryPath(context, (int)row["CategoryId"]), (decimal)row["Price"],
                                          (int)row["AdType"], (int)row["AdLevel"], (int)row["AdStatus"],
                                          (DateTime)row["DateCreated"], (DateTime)row["DateApproved"], (DateTime)row["ExpirationDate"], row["Description"].ToString(), row["Url"].ToString(), 0)).ToArray<CachedAdvertisment>();

                        }

                        if (advArr != null && advArr.Count() > 0)
                        {
                            advColl.CopyTo(advArr, 0);
                            DateTime expiration = DateTime.Now.AddMinutes(CacheLifeTime);
                            context.Cache.Add(cacheKey, advColl, null, expiration, TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Normal, null);
                        }
                    }
                }
            }
            catch (SqlException SQLEX)
            {
                Oplaco.Exceptions.AppService.ProcessAndNotifyDataAccessLayerException(SQLEX);
            }
            catch (Exception EX)
            {
                Oplaco.Exceptions.AppService.ProcessAndNotifyBusinessLayerException(EX);
            }

            return advColl;
        }
        
        /// <summary>
        /// FetchByQuery; basically fires queries based on params to database, without caching
        /// </summary>
        /// <param name="categoryId">id of the category, if given 0, it won't query on this param</param>
        /// <param name="memberId">id of the registered user, if given 0, it won't query on this param</param>
        /// <param name="maximumPrice">maximum price of the ad</param>
        /// <param name="searchtext"></param>
        /// <param name="adtype"></param>
        /// <param name="adlevel"></param>
        /// <param name="dayrange"></param>
        /// <param name="withImageId"></param>
        /// <param name="maximumItems"></param>
        /// <returns>Cached Ads Collection object</returns>
        public static CachedAdvertismentCollection FetchByQuery(int categoryId, int memberId, int maximumPrice, string searchtext, AdType adtype, AdLevel adlevel, int dayrange, bool withImageId, int maximumItems)
        {            
            CachedAdvertismentCollection advColl = new CachedAdvertismentCollection();

            try
            {
                if (dayrange == 0) dayrange = settings.MaxAdRunningDays;
                Oplaco.Core.DAL.AdsDataComponent.AdsDataTable data = AdsDB.GetActiveAdsByQuery(maximumItems, categoryId, memberId, new decimal(maximumPrice), searchtext, String.Empty, (int)adtype, (int)adlevel, dayrange, withImageId);

                if (data != null && data.Count > 0)
                {
                    CachedAdvertisment[] advArr = null;
                    if (withImageId)
                    {
                        advArr = (from DataRow row in data.Rows
                                  select new CachedAdvertisment((int)row["Id"],
                                      (int)row["MemberId"], 
                                      (int)row["CategoryId"], 
                                      row["Title"].ToString(),
                                      CategoryManager.GetCategoryPath(null, (int)row["CategoryId"]),
                                      row["CategoryName"].ToString(), 
                                      (decimal)row["Price"],
                                      (int)row["AdType"],
                                      (int)row["AdLevel"],
                                      (int)row["AdStatus"], 
                                      (DateTime)row["DateCreated"], 
                                      (DateTime)row["DateApproved"], 
                                      (DateTime)row["ExpirationDate"], 
                                      row["Description"].ToString(), 
                                      row["Url"].ToString(), 
                                      (int)row["PreviewImageId"])).ToArray<CachedAdvertisment>();

                        
                        
                    }
                    else
                    {
                        advArr = (from DataRow row in data.Rows
                                  select new CachedAdvertisment((int)row["Id"],
                                      (int)row["MemberId"], (int)row["CategoryId"], row["Title"].ToString(), row["CategoryName"].ToString(), CategoryManager.GetCategoryPath(null,(int)row["CategoryId"]), (decimal)row["Price"],
                                      (int)row["AdType"], (int)row["AdLevel"], (int)row["AdStatus"],
                                      (DateTime)row["DateCreated"], (DateTime)row["DateApproved"], (DateTime)row["ExpirationDate"], row["Description"].ToString(), row["Url"].ToString(), 0)).ToArray<CachedAdvertisment>();


                    }


                    if (advArr != null && advArr.Count() > 0)
                    {
                        
                        advColl.CopyTo(advArr, 0);
                    }
                }
            }
            catch (SqlException SQLEX)
            {
                Oplaco.Exceptions.AppService.ProcessAndNotifyDataAccessLayerException(SQLEX);
            }
            catch (Exception EX)
            {
                Oplaco.Exceptions.AppService.ProcessAndNotifyBusinessLayerException(EX);
            }

            return advColl;
        }

        /// <summary>
        /// Fetches without caching
        /// </summary>
        /// <param name="maximumItems"></param>
        /// <returns></returns>
        public static CachedAdvertismentCollection Fetch(int maximumItems)
        {
            try
            {
                Oplaco.Core.DAL.AdsDataComponent.AdsDataTable data = AdsDB.GetActiveAdsByQuery(maximumItems, 0, 0, 10000000, String.Empty, String.Empty, (int)AdType.Unspecified, (int)AdLevel.Unspecified, settings.MaxAdRunningDays, false);
                CachedAdvertismentCollection advColl = new CachedAdvertismentCollection();
                if (data != null && data.Count > 0)
                {

                    CachedAdvertisment[] advArr = (from DataRow row in data.Rows
                                                   select new CachedAdvertisment((int)row["Id"],
                                                       (int)row["MemberId"], (int)row["CategoryId"], row["Title"].ToString(), row["CategoryName"].ToString(), CategoryManager.GetCategoryPath(null, (int)row["CategoryId"]), (decimal)row["Price"],
                                                       (int)row["AdType"], (int)row["AdLevel"], (int)row["AdStatus"], 
                                                       (DateTime)row["DateCreated"], (DateTime)row["DateApproved"], (DateTime)row["ExpirationDate"], row["Description"].ToString(), row["Url"].ToString(), 0)).ToArray<CachedAdvertisment>();

                    if (advArr != null && advArr.Count() > 0) advColl.CopyTo(advArr, 0);
                    return advColl;
                }
            }
            catch (SqlException SQLEX)
            {
                Oplaco.Exceptions.AppService.ProcessAndNotifyDataAccessLayerException(SQLEX);
            }
            catch (Exception EX)
            {
                Oplaco.Exceptions.AppService.ProcessAndNotifyBusinessLayerException(EX);
            }
            return null;
        }

        
        #endregion

        #region Private Methods
        /// <summary>
        /// Fetches cachekey
        /// </summary>
        /// <param name="featureCacheNumber"></param>
        /// <returns></returns>
        private static string GetCacheKey(int featureCacheNumber)
        {
            return CacheKeyPrefix + featureCacheNumber.ToString();
        }


        
        #endregion

    }
}
